﻿using UnityEngine;
using LuaInterface;
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Collections;

public class LuaMethod
{
    public string name;
    public LuaCSFunction func;
    public LuaMethod(string str, LuaCSFunction f)
    {
        name = str;
        func = f;
    }
}

public class LuaHelper
{
    public static class LoadScript
    {
        private static Dictionary<string, string> luaPaths = new Dictionary<string, string>();
        public static void libLoad()
        {
            systemfunction.registerFunc();
        }

        public static void scriptLoad(string[] files)
        {
            string scriptPath = app.AppPersistentPath.getScriptPath();
            if (files == null)
            {
                files = Directory.GetFiles(scriptPath, "*.lua", SearchOption.AllDirectories);
            }
            else {
                for (int i = 0; i < files.Length; i++) {
                    files[i] = scriptPath + "/" + files[i];
                }
            }
            for (int i = 0; i < files.Length; i++)
            {
                string luaFileName = Path.GetFileName(files[i]);

                if (luaPaths.ContainsKey(luaFileName) == false)
                {
                    LuaHelper.getLuaModule().loadScript(files[i], scriptPath);
                    luaPaths.Add(luaFileName, files[i]);
                }
            }
        }

        public static void load()
        {
            if (LuaHelper.UsePbc == true)
            {
                LuaDLL.luaopen_protobuf_c(LuaHelper.getLuaModule().luaState); //pbc
                LuaDLL.luaopen_lpeg(LuaHelper.getLuaModule().luaState);//lpeg
                LoadScript.scriptLoad(new string[] { "util/pbc/protobuf.lua", "util/pbc/parser.lua" });
            }
            libLoad();
            scriptLoad(new string[]{ "/util/util.lua" });
            scriptLoad(null);
            Debug.Log("lua 脚本文件载入成功");
        }
    }
    internal static LuaCSFunction traceCallback = new LuaCSFunction(traceback);
    internal static LuaCSFunction panicCallback = new LuaCSFunction(panic);
    protected static System.Text.StringBuilder textBuilder = new System.Text.StringBuilder(128);
    protected static int DOUBLE_LIMIT = 999999;
    protected static LuaHelper sLuaModule = new LuaHelper();
    protected static Dictionary<string, bool> sLuaCache = new Dictionary<string, bool>();
    protected IntPtr luaState;
    public static bool UsePbc = true;                           //PBC

    public static LuaHelper getLuaModule()
    {
        return sLuaModule;
    }
    public IntPtr getLuaState()
    {
        return luaState;
    }

    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    public static int traceback(IntPtr l)
    {
        LuaDLL.lua_getglobal(l, "debug");
        LuaDLL.lua_getfield(l, -1, "traceback");
        LuaDLL.lua_pushvalue(l, 1);
        LuaDLL.lua_pushnumber(l, 2);
        LuaDLL.lua_call(l, 2, 1);
        return 1;
    }
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    public static int panic(IntPtr l)
    {
        string reason = String.Format("unprotected error in call to Lua API ({0})", LuaDLL.lua_tostring(l, -1));
        LuaDLL.lua_pop(l, 1);
        Debug.LogError(reason);
        return 0;
    }
    public LuaHelper()
    {
        luaState = LuaDLL.luaL_newstate();
        FBLuaDebugger.initDebug(luaState);
        LuaDLL.luaL_openlibs(luaState);
        traceCallback = new LuaCSFunction(traceback);
        panicCallback = new LuaCSFunction(panic);
        LuaDLL.lua_atpanic(luaState, panicCallback);    
    }
    public void luaError(string error)
    {
        LuaDLL.luaL_error(luaState, error);
    }
    public void registerLib(string name, LuaMethod[] func)
    {
        luaBeginTable();
        for (int i = 0; i < func.Length; i++)
        {
            LuaDLL.lua_pushstring(luaState, func[i].name);
            LuaDLL.lua_pushstdcallcfunction(luaState, func[i].func);
            LuaDLL.lua_settable(luaState, -3);
        }
        luaEndTable(name);
    }
    public void luaBeginTable()
    {
        LuaDLL.lua_newtable(luaState);
    }
    public void luaEndTable(string tableName)
    {
        LuaDLL.lua_setglobal(luaState, tableName);
    }
    public void errorTrace(int errorType)
    {
        string err = LuaDLL.lua_tostring(luaState, -1);
        if (errorType == (int)LuaThreadStatus.LUA_ERRSYNTAX)
            err = "lua error: 编译时期错误\r\n" + err;
        else if (errorType == (int)LuaThreadStatus.LUA_ERRMEM)
            err = "lua error: 内存分配错误\r\n" + err;
        else if (errorType == (int)LuaThreadStatus.LUA_ERRRUN)
            err = "lua error: 运行时错误\r\n" + err;
        else if (errorType == (int)LuaThreadStatus.LUA_ERRERR)
            err = "lua error: 错误处理时发生错误\r\n" + err;
        else if (errorType == (int)LuaThreadStatus.LUA_ERRERR)
            err = "lua error: 协程发生错误\r\n" + err;

        LuaDLL.lua_pop(luaState, 1);
        if (err == null)
            err = "Unknown Lua Error";

        Debug.LogError(err);
    }
    public void loadScript(string fileName, string parentPath)
    {
        string name = fileName.Remove(0, parentPath.Length);
        if (sLuaCache.ContainsKey(name) == true)
            return;

        if (File.Exists(fileName) == false)
            return;

        byte[] byteCode = File.ReadAllBytes(fileName);
        if (byteCode == null)
        {
            Debug.LogError("lua文件 - " + fileName + "加载失败");
            return;
        }

        sLuaCache.Add(name, true);
        LuaDLL.lua_pushstdcallcfunction(luaState, traceCallback);
        int oldTop = LuaDLL.lua_gettop(luaState);
        int luaError = LuaDLL.luaL_loadbuffer(luaState, byteCode, byteCode.Length, name);
        if (luaError != 0)
        {
            errorTrace(luaError);
            return;
        }

        luaError = LuaDLL.lua_pcall(luaState, 0, 0, oldTop);
        if (luaError != 0)
        {
            errorTrace(luaError);
            return;
        }

        LuaDLL.lua_settop(luaState, oldTop - 1);
    }
    public void doString(string luaText)
    {
        byte[] bt = Encoding.UTF8.GetBytes(luaText);
        LuaDLL.lua_pushstdcallcfunction(luaState, traceCallback);
        int oldTop = LuaDLL.lua_gettop(luaState);
        int luaError = LuaDLL.luaL_loadbuffer(luaState, bt, bt.Length, "chunk");
        if (luaError != 0)
        {
            errorTrace(luaError);
            return;
        }

        luaError = LuaDLL.lua_pcall(luaState, 0, 0, oldTop);
        if (luaError != 0)
        {
            errorTrace(luaError);
            return;
        }

        LuaDLL.lua_settop(luaState, oldTop - 1);
    }
    public object callScript(string funcName, params object[] args)
    {
        LuaDLL.lua_pushstdcallcfunction(luaState, traceCallback);
        int oldTop = LuaDLL.lua_gettop(luaState);
        if (LuaDLL.lua_checkstack(luaState, args.Length + 6) == false)
        {
            LuaDLL.lua_settop(luaState, oldTop - 1);
            Debug.LogError("Lua stack overflow");
            return null;
        }

        LuaDLL.lua_getglobal(luaState, funcName);
        int argCount = args.Length;
        for (int i = 0; i < argCount; i++)
            pushLuaData(args[i]);

        object returnValue = null;
        int luaError = LuaDLL.lua_pcall(luaState, argCount, 1, oldTop);
        if (luaError != 0)
        {
            errorTrace(luaError);
            return returnValue;
        }

        //TraceBack被放在了最后面（这里是-2)，然后是返回值(这里是-1)
        LuaTypes type = LuaDLL.lua_type(luaState, -1);
        if (type == LuaTypes.LUA_TNUMBER)
            returnValue = LuaDLL.lua_tonumber(luaState, -1);
        if (type == LuaTypes.LUA_TBOOLEAN)
            returnValue = LuaDLL.lua_toboolean(luaState, -1);
        if (type == LuaTypes.LUA_TSTRING)
            returnValue = LuaDLL.lua_tostring(luaState, -1);

        // 如果Lua没有返回值，那么默认返回0
        if (LuaDLL.lua_isnil(luaState, -1) == true)
            returnValue = null;

        LuaDLL.lua_settop(luaState, oldTop - 1);
        return returnValue;
    }
    public void pushListLuaData(ArrayList objs)
    {
        LuaDLL.lua_newtable(luaState);// 创建lua表
        int index = 1;
        foreach (object obj in objs)
        {
            LuaDLL.lua_pushnumber(luaState, index);
            pushLuaData(obj);
            LuaDLL.lua_settable(luaState, -3);
            index++;
        }
    }
    public void pushLuaData(object obj)
    {
        if (obj == null)
            LuaDLL.lua_pushnil(luaState);
        else if (obj is byte[])
        {
            byte[] buff = (byte[])obj;
            LuaDLL.lua_pushlstring(luaState, buff, buff.Length);
        }
        else if (obj is bool)
        {
            LuaDLL.lua_pushboolean(luaState, (bool)obj);
        }
        else if (obj is byte)
        {
            LuaDLL.lua_pushnumber(luaState, (byte)obj);
        }
        else if (obj is short)
        {
            LuaDLL.lua_pushnumber(luaState, (short)obj);
        }
        else if (obj is int)
        {
            LuaDLL.lua_pushnumber(luaState, (int)obj);
        }
        else if (obj is long)
        {
            LuaDLL.lua_pushnumber(luaState, (long)obj);
        }
        else if (obj is float)
        {
            LuaDLL.lua_pushnumber(luaState, (float)obj);
        }
        else if (obj is double)
        {
            LuaDLL.lua_pushnumber(luaState, (double)obj);
        }
        else if (obj is string)
        {
            LuaDLL.lua_pushstring(luaState, (string)obj);
        }
        else if (obj is ArrayList)
        {
            pushListLuaData((ArrayList)obj);
        }
        else
        {
            Debug.Log("pushLuaData error haven't type = " + obj.GetType());
            throw new Exception("pushLuaData error haven't type = " + obj.GetType());
        }
    }
    
    // 将lua中的数据 放入ByteArray
    public void luaTablePushByteArray(ByteArray stream, int index)
    {
        // nil 入栈作为初始 key
        LuaDLL.lua_pushnil(luaState);
        while (LuaDLL.lua_next(luaState, index) != 0)
        {
            LuaTypes type = LuaDLL.lua_type(luaState, -1);
            LuaTypes keyType = LuaDLL.lua_type(luaState, -2);
            if (type == LuaTypes.LUA_TNUMBER)
            {
                if (keyType == LuaTypes.LUA_TNUMBER)
                {
                    double keyValue = LuaDLL.lua_tonumber(luaState, -2);
                    if (keyValue >= DOUBLE_LIMIT)
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                        stream.PushValue(keyValue);
                    }
                    else
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                        stream.PushValue((float)keyValue);
                    }
                }
                else if (keyType == LuaTypes.LUA_TSTRING)
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
                    stream.PushValue(LuaDLL.lua_tostring(luaState, -2));
                }

                double value = LuaDLL.lua_tonumber(luaState, -1);
                if (value >= DOUBLE_LIMIT)
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                    stream.PushValue(value);
                }
                else
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                    stream.PushValue((float)value);
                }
            }
            else if (type == LuaTypes.LUA_TBOOLEAN)
            {
                if (keyType == LuaTypes.LUA_TNUMBER)
                {
                    double keyValue = LuaDLL.lua_tonumber(luaState, -2);
                    if (keyValue >= DOUBLE_LIMIT)
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                        stream.PushValue(keyValue);
                    }
                    else
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                        stream.PushValue((float)keyValue);
                    }
                }
                else if (keyType == LuaTypes.LUA_TSTRING)
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
                    stream.PushValue(LuaDLL.lua_tostring(luaState, -2));
                }

                stream.PushValue((byte)ByteArray.EDataType.TYPE_BOOLEAN);
                stream.PushValue(LuaDLL.lua_toboolean(luaState, -1));
            }
            else if (type == LuaTypes.LUA_TSTRING)
            {
                if (keyType == LuaTypes.LUA_TNUMBER)
                {
                    double keyValue = LuaDLL.lua_tonumber(luaState, -2);
                    if (keyValue >= DOUBLE_LIMIT)
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                        stream.PushValue(keyValue);
                    }
                    else
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                        stream.PushValue((float)keyValue);
                    }
                }
                else if (keyType == LuaTypes.LUA_TSTRING)
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
                    stream.PushValue(LuaDLL.lua_tostring(luaState, -2));
                }

                stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
                stream.PushValue(LuaDLL.lua_tostring(luaState, -1));
            }
            else if (type == LuaTypes.LUA_TTABLE)
            {
                if (keyType == LuaTypes.LUA_TNUMBER)
                {
                    double keyValue = LuaDLL.lua_tonumber(luaState, -2);
                    if (keyValue >= DOUBLE_LIMIT)
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                        stream.PushValue(keyValue);
                    }
                    else
                    {
                        stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                        stream.PushValue((float)keyValue);
                    }
                }
                else if (keyType == LuaTypes.LUA_TSTRING)
                {
                    stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
                    stream.PushValue(LuaDLL.lua_tostring(luaState, -2));
                }

                stream.PushValue((byte)ByteArray.EDataType.TYPE_TABLE);
                luaTablePushByteArray(stream, LuaDLL.lua_gettop(luaState));
            }
            // 现在栈顶（-1）是 value，-2 位置是对应的 key
            // 这里可以判断 key 是什么并且对 value 进行各种处理
            // 弹出 value，让 key 留在栈顶
            LuaDLL.lua_pop(luaState, 1);
        }
        stream.PushValue((byte)0);
    }
    public void luaPushByteArray(ByteArray stream, int index)
    {
        int top = index;
        if (LuaDLL.lua_isnil(luaState, top) == true)
        {
            string errorDesc;
            errorDesc = "参数[" + top + "]是一个nil值";
            throw new Exception(errorDesc);
        }

        LuaTypes type = LuaDLL.lua_type(luaState, top);
        if (type == LuaTypes.LUA_TNUMBER)
        {
            double value = LuaDLL.lua_tonumber(luaState, top);
            if (value >= DOUBLE_LIMIT)
            {
                stream.PushValue((byte)ByteArray.EDataType.TYPE_DOUBLE);
                stream.PushValue(value);
            }
            else
            {
                stream.PushValue((byte)ByteArray.EDataType.TYPE_FLOAT);
                stream.PushValue((float)value);
            }
        }
        else if (type == LuaTypes.LUA_TBOOLEAN)
        {
            stream.PushValue((byte)ByteArray.EDataType.TYPE_BOOLEAN);
            stream.PushValue((bool)LuaDLL.lua_toboolean(luaState, top));
        }
        else if (type == LuaTypes.LUA_TSTRING)
        {
            stream.PushValue((byte)ByteArray.EDataType.TYPE_STRING);
            stream.PushValue(LuaDLL.lua_tostring(luaState, top));
        }
        else if (type == LuaTypes.LUA_TTABLE)
        {
            stream.PushValue((byte)ByteArray.EDataType.TYPE_TABLE);
            luaTablePushByteArray(stream, top);
        }
    }

    // 将stream中的数据放入lua中
    public void byteArrayPushLua(ByteArray stream)
    {
        byte dataType = 0;
        stream.PopValue(ref dataType);
        if (dataType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
        {
            double value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_FLOAT)
        {
            float value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_USHORT)
        {
            ushort value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_SHORT)
        {
            short value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_UCHAR)
        {
            byte value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_CHAR)
        {
            sbyte value = 0;
            stream.PopValue(ref value);
            LuaDLL.lua_pushnumber(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_BOOLEAN)
        {
            bool value = false;
            stream.PopValue(ref value);
            LuaDLL.lua_pushboolean(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_STRING)
        {
            string value = "";
            stream.PopValue(ref value);
            LuaDLL.lua_pushstring(luaState, value);
        }
        else if (dataType == (byte)ByteArray.EDataType.TYPE_TABLE)
        {
            byteArrayPushLuaTable(stream);
        }
    }
    public void byteArrayPushLuaTable(ByteArray stream)
    {
        luaBeginTable();

        byte keyType = 0;
        string stringKey = string.Empty;
        double doubleKey = 0;
        float floatKey = 0;
        ushort ushortKey = 0;
        short shortKey = 0;
        byte byteKey = 0;
        sbyte sbyteKey = 0;
        for (stream.PopValue(ref keyType); keyType != 0; stream.PopValue(ref keyType))
        {
            if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                stream.PopValue(ref doubleKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                stream.PopValue(ref floatKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                stream.PopValue(ref ushortKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                stream.PopValue(ref shortKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                stream.PopValue(ref byteKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                stream.PopValue(ref sbyteKey);
            else if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                stream.PopValue(ref stringKey);

            byte dataType = 0;
            stream.PopValue(ref dataType);
            if (dataType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
            {
                double value = 0.0f;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_FLOAT)
            {
                float value = 0.0f;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_USHORT)
            {
                ushort value = 0;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_SHORT)
            {
                short value = 0;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_UCHAR)
            {
                byte value = 0;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_CHAR)
            {
                sbyte value = 0;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_BOOLEAN)
            {
                bool value = false;
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_STRING)
            {
                string value = "";
                stream.PopValue(ref value);
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    fieldPushLuaTable(stringKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    fieldPushLuaTable(ushortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    fieldPushLuaTable(shortKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    fieldPushLuaTable(byteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    fieldPushLuaTable(sbyteKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    fieldPushLuaTable(floatKey, value);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    fieldPushLuaTable(doubleKey, value);
            }
            else if (dataType == (byte)ByteArray.EDataType.TYPE_TABLE)
            {
                if (keyType == (byte)ByteArray.EDataType.TYPE_STRING)
                    LuaDLL.lua_pushstring(luaState, stringKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_USHORT)
                    LuaDLL.lua_pushnumber(luaState, ushortKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_SHORT)
                    LuaDLL.lua_pushnumber(luaState, shortKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_UCHAR)
                    LuaDLL.lua_pushnumber(luaState, byteKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_CHAR)
                    LuaDLL.lua_pushnumber(luaState, sbyteKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_FLOAT)
                    LuaDLL.lua_pushnumber(luaState, floatKey);
                else if (keyType == (byte)ByteArray.EDataType.TYPE_DOUBLE)
                    LuaDLL.lua_pushnumber(luaState, doubleKey);

                byteArrayPushLuaTable(stream);
                LuaDLL.lua_settable(luaState, -3);
            }
        }
    }
    public void fieldPushLuaTable(double index, object value)
    {
        LuaDLL.lua_pushnumber(luaState, index);
        objectPushLua(value);
        LuaDLL.lua_settable(luaState, -3);
    }
    public void fieldPushLuaTable(string fieldName, object value)
    {
        LuaDLL.lua_pushstring(luaState, fieldName);
        objectPushLua(value);
        LuaDLL.lua_settable(luaState, -3);
    }
    public void objectPushLua(object value)
    {
        string type = value.GetType().Name;
        if (type == "Byte[]")
        {
            byte[] byteValue = (byte[])value;
            LuaDLL.lua_pushlstring(luaState, byteValue, (int)byteValue.Length);
            return;
        }
        else if (type == "Byte")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToByte(value));
            return;
        }
        else if (type == "SByte")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToSByte(value));
            return;
        }
        else if (type == "UInt16")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToUInt16(value));
            return;
        }
        else if (type == "Int16")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToInt16(value));
            return;
        }
        else if (type == "Int32")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToInt32(value));
            return;
        }
        else if (type == "UInt32")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToDouble(value));
            return;
        }
        else if (type == "Int64")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToInt64(value));
            return;
        }
        else if (type == "UInt64")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToUInt64(value));
            return;
        }
        else if (type == "Boolean")
        {
            LuaDLL.lua_pushboolean(luaState, Convert.ToBoolean(value));
            return;
        }
        else if (type == "Single")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToDouble(value));
            return;
        }
        else if (type == "Double")
        {
            LuaDLL.lua_pushnumber(luaState, Convert.ToDouble(value));
            return;
        }
        else if (type == "String")
        {
            LuaDLL.lua_pushstring(luaState, Convert.ToString(value));
            return;
        }

        throw new Exception("不支持的数据类型 - " + type);
    }
}
